#include "project_tasks.h"
#include <stdio.h>


/* --- 全局同步原语句柄定义 --- */

SemaphoreHandle_t xUartMutex;
QueueHandle_t xSensorDataQueue;
QueueHandle_t xOledDataQueue;
QueueHandle_t xBleCmdQueue;
EventGroupHandle_t xBLEEventGroup;
EventGroupHandle_t xBLE_App_State;

QueueSetHandle_t xQueueSet_OLED;
QueueSetHandle_t xReporterQueueSet;

TaskHandle_t xUartProcessTaskHandle = NULL;

/**
 * @brief 传感器任务：负责周期性读取MAX30102数据。
 *
 * 该任务会周期性地从MAX30102传感器读取心率和血氧数据。
 * 读取完成后，它会将数据封装成一个SensorData_t结构体，
 * 并发送到 xSensorDataQueue 队列中，供其他任务消费。
 * 任务会使用 vTaskDelay 进行周期性延时，以控制采样频率。
 * 它会响应紧急上报命令，临时采样一次，触发上报任务
 */
void Task_MAX30102_Sensor(void *pvParameters) {
	SensorData_t sensor_data;

	max30102_init_buffer();

	for (;;)
	{
		xEventGroupWaitBits(
				xBLE_App_State,
				BIT_APP_BLE_CONNECTED,
				pdTRUE, // 等待后自动清除事件位
				pdFALSE, // 等待任一位被设置
				portMAX_DELAY //永久阻塞，直到连接成功
		);
		printf("Sensor Task: BLE connected. Starting sampling loop.\n");

		while (1)
		{
			EventBits_t uxBits = xEventGroupWaitBits(
					xBLE_App_State,
					BIT_FORCE_SAMPLE | BIT_APP_BLE_DISCONNECTED, // 同时等待强制采样和断开连接事件
					pdTRUE,  // 等待后清除事件位
					pdFALSE,
					pdMS_TO_TICKS(10000) // 10秒超时，作为常规采样周期
			);

			// 如果收到断开连接事件，跳出此内层循环，重新回到外层循环等待连接
			if ((uxBits & BIT_APP_BLE_DISCONNECTED) != 0)
			{
				printf("Sensor Task: BLE disconnected. Returning to waiting state.\n");
				break; // 跳出 while(1) 循环，进入外层循环的下一次迭代
			}

			// 如果收到强制采样事件，或者等待超时（常规周期到了），则进行采样
			if ((uxBits & BIT_FORCE_SAMPLE) != 0 || (uxBits == 0))
			{
				// 执行传感器采样
				printf("Sensor Task: Sampling data...\n");
				sensor_data = max30102_process_data();

				// 将数据发送到队列
				xQueueSend(xSensorDataQueue, &sensor_data, 0);
				xQueueSend(xOledDataQueue, &sensor_data, 0);
			}
		}
	}
}

/**
 * @brief 显示任务：负责在OLED屏幕上显示数据。
 * 该任务会阻塞在 xSensorDataQueue队列上，
 * 接收来自传感器任务的数据。
 */
void Task_OLED_Display(void *pvParameters)
{
	OLED_Init();
	OLED_Display_On();

    for (;;)
    {
    	SensorData_t sensor_data;

		if (xQueueReceive(xOledDataQueue, &sensor_data, portMAX_DELAY) == pdPASS)
		{
			// 显示心率、血氧
			OLED_Clear();
			OLED_ShowString(0, 0, "HR:", OLED_FONT16);
			OLED_ShowNum(40, 0, sensor_data.heart_rate, 3, OLED_FONT16);
			OLED_ShowString(0, 2, "SpO2:", OLED_FONT16);
			OLED_ShowNum(60, 2, sensor_data.spo2, 3, OLED_FONT16);
		}
    }
}

/**
 * @brief NTP同步任务：负责同步网络时间。
 *
 * 该任务会通过NTP协议连接网络，周期性地同步当前时间。
 * 为了节省功耗和网络资源，该任务的同步周期设置为一小时。
 */
void Task_NTP_Sync(void *pvParameters)
{

    // 初始化 NTP 客户端和 WiFi 连接
    if (ntp_init_and_connect(xUartMutex) != NTP_SUCCESS)
    {
        printf("Initialization failed, suspending task.\r\n");
        vTaskDelay(pdMS_TO_TICKS(600000)); //if初始化失败十分钟后重试
    }

    for (;;)
    {
    	rtc_time_t synced_time;

        if (ntp_sync_and_get_time_with_lock(xUartMutex, &synced_time) == NTP_SUCCESS)
        {
            printf("NTP Sync: Synchronization successfuly!\r\n");
        }
        else
        {
            printf("NTP Sync: Synchronization failed.\r\n");
        }

        vTaskDelay(pdMS_TO_TICKS(3600000)); // 每小时同步一次
    }
}

/**
 * @brief 蓝牙上报任务：负责将数据上报给树莓派。
 *
 * 该任务通过阻塞等待 xSensorDataQueue中的数据
 * 正常情况下，它会从队列中接收数据并上报。
 * 当 xBLE_App_State 中的 BIT_FORCE_SAMPLE 事件被设置时，
 * 传感器会立即采样一次，队列中有数据该任务就会report，从而实现即时响应。
 */
void Task_BLE_Reporter(void *pvParameters) {

	SensorData_t sensor_data;

    for (;;)
    {
        if (xQueueReceive(xSensorDataQueue, &sensor_data, portMAX_DELAY) == pdPASS)
        {
                printf("BLE Reporter: Received from queue -> Heart Rate: %d, SpO2: %d\r\n",
                       sensor_data.heart_rate, sensor_data.spo2);

                // 发送数据，将互斥锁作为参数传入
                ble_send_sensor_data(xUartMutex, sensor_data.heart_rate, sensor_data.spo2);
        }
    }
}

/**
 * @brief 蓝牙接收任务：负责接收来自树莓派的命令。
 *
 * 该任务处理BLE的接收回调。当它通过BLE接收到来自树莓派的命令时，
 * 它会根据命令内容执行相应的操作。例如，如果接收到 "report_now" 命令，
 * 它会设置 xBLEEventGroup 中的 BIT_FORCE_SAMPLE 事件位，
 * 以通知上报任务立即执行上报。
 * 如果接收到阈值超出警告，会控制蜂鸣器报警
 */
void Task_BLE_Receiver(void *pvParameters) {

	BleCommand_t received_cmd;

    for (;;)
    {
    	//阻塞等待下发的命令
    	if(xQueueReceive(xBleCmdQueue, &received_cmd, portMAX_DELAY) == pdPASS )
    	{
    		//printf("BLE Receiver: Received 'report_now' command.\n");

    		switch(received_cmd.type)
    		{
    			case BLE_CMD_REPORT_NOW:
    				printf("BLE Receiver: Received 'Report now' command.\r\n");
    				xEventGroupSetBits(xBLE_App_State, BIT_FORCE_SAMPLE); //通知传感器任务立即采样
    				break;
    			case BLE_CMD_BEEPER_WARNING:
    				printf("BLE Receiver: Received 'Warning' command, triggering beeper alarm.\r\n");
    				beep_start(2, 300);
    				break;
    			default:
    				printf("BLE Receive: Received unknown command.\r\n");
    		}
    	}
    }
}


/**
 * @brief 蓝牙连接状态管理任务：负责管理蓝牙连接状态。
 * 初始化BLE，发布广播报文，以供树莓派发现
 * 接收到+BLECONN，会设置BIT_APP_BLE_CONNECTED事件位使传感器开始采样
 * 接收到+BLEDISCONN，会设置BIT_APP_BLE_DISCONNECTED事件位使传感器停止采样，相应的，上报任务也会停止
 * 接收到+BLEDISSCONN，将重新发送广播(重试三次)
 * */
void Task_BLE_Manager(void *pvParameters)
{
	int init_result = ble_module_init(xUartMutex);

    if (init_result != BLE_INIT_SUCCESS)
    {
        printf("BLE module initialization failed with error code: %d. Halting.\r\n", init_result);
        vTaskSuspend(NULL);
    }

	for(;;)
	{
		printf("Inside manageer task\r\n");

        EventBits_t uxBits = xEventGroupWaitBits(
            xBLEEventGroup,
            BIT_BLE_CONNECTED | BIT_BLE_DISCONNECTED,
			pdTRUE, // 等待后清除事件位
            pdFALSE, // 等待任一位被设置
            portMAX_DELAY // 永久阻塞
        );

        if ((uxBits & BIT_BLE_CONNECTED) != 0)  //CONNECTED
        {
            printf("BLE Status: CONNECTED\r\n");
            xEventGroupClearBits(xBLE_App_State, BIT_APP_BLE_DISCONNECTED);
            xEventGroupSetBits(xBLE_App_State, BIT_APP_BLE_CONNECTED);
        }

        if ((uxBits & BIT_BLE_DISCONNECTED) != 0) //DISCONNECTED
        {
            printf("BLE Status: DISCONNECTED\r\n");
            xEventGroupClearBits(xBLE_App_State, BIT_APP_BLE_CONNECTED);
            xEventGroupSetBits(xBLE_App_State, BIT_APP_BLE_DISCONNECTED);
            ble_adv_start(xUartMutex);  // 发送 AT+BLEADVERTSTART 重新开始广播
        }

	}
}


/* 从环形缓冲区中读取数据，解析并根据不同的内容分发
 * 该任务采用事件驱动模式，而非忙等轮询，它会阻塞来自UART中断的通知，
 * 只有在接收到新数据时才会被唤醒并进行处理，从而高效地利用CPU资源
 */
void Task_UART_Daemon(void *pvParameters)
{
	xUartProcessTaskHandle = xTaskGetCurrentTaskHandle();

	uart_comm_init(&huart2);

	for(;;)
	{
		ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

		uart_process_received_data();

	}
}
